package com.vodden.money.shared;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;

import javax.jdo.annotations.Element;
import javax.jdo.annotations.Extension;
import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;


/* TODO this class is totally capable of implementing
 * the java.util.List collection interface, but that
 * creates a many to many relationship in the google app 
 * engine datastore which at the time of writing isn't supported.
 */
@PersistenceCapable
public class EntryGroup implements Serializable, Iterable<Entry> {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@PrimaryKey
	@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
	@Extension(vendorName = "datanucleus", key = "gae.encoded-pk", value = "true")
	String id;
	@Persistent
	Integer balance;
	@Persistent
	Date startOfRange;
	@Persistent
	Date endOfRange;
	@Persistent(mappedBy = "parent")
	@Element(dependent = "true")
	LinkedList<Entry> entries;
	
	public EntryGroup() {
		balance = new Integer(0);
		entries = new LinkedList<Entry>();
	}

	public void update(Entry entry, Integer newValue) {
		Integer oldValue = entry.getValue();
		if (oldValue != null ) {
			balance = balance - oldValue;
		}
		balance = balance + newValue;
	}
	
	
	public void add(int index, Entry entry) {
		entries.add(index, entry);
		balance += entry.getValue();
		entry.setParent(this);
	}

	
	public Entry remove(int index) {
		Entry returnValue = entries.remove(index);
		balance += returnValue.getValue();
		return returnValue;
	}

	
	public boolean add(Entry entry) {
		balance += entry.getValue();
		entry.setParent(this);
		return entries.add(entry);
	}

	
	public boolean addAll(Collection<? extends Entry> entriesToAdd) {
		for (Entry entry : entriesToAdd) {
			balance += entry.getValue();
			entry.setParent(this);
		}
		return entries.addAll(entriesToAdd);
	}

	
	public boolean addAll(int index, Collection<? extends Entry> entriesToAdd) {
		for (Entry entry : entriesToAdd) {
			balance += entry.getValue();
		}
		return entries.addAll(entriesToAdd);
	}

	
	public void clear() {
		entries.clear();
		balance = 0;
	}

	
	public boolean contains(Object arg0) {
		return entries.contains(arg0);
	}

	
	public boolean containsAll(Collection<?> arg0) {
		return entries.contains(arg0);
	}

	
	public Entry get(int arg0) {
		return entries.get(arg0);
	}

	
	public int indexOf(Object arg0) {
		return entries.indexOf(arg0);
	}

	
	public boolean isEmpty() {
		return entries.isEmpty();
	}

	
	public Iterator<Entry> iterator() {
		return entries.iterator();
	}

	
	public int lastIndexOf(Object arg0) {
		return entries.lastIndexOf(arg0);
	}

	
	public ListIterator<Entry> listIterator() {
		return entries.listIterator();
	}

	
	public ListIterator<Entry> listIterator(int arg0) {
		return entries.listIterator(arg0);
	}

	
	public int size() {
		return entries.size();
	}

	
	public List<Entry> subList(int arg0, int arg1) {
		return entries.subList(arg0, arg1);
	}

	
	public Object[] toArray() {
		return entries.toArray();
	}

	
	public <T> T[] toArray(T[] arg0) {
		return entries.toArray(arg0);
	}

	
	public boolean remove(Object o) throws UnsupportedOperationException {
		UnsupportedOperationException exception = new UnsupportedOperationException();
		throw exception;
	}

	
	public boolean removeAll(Collection<?> c)
			throws UnsupportedOperationException {
		UnsupportedOperationException exception = new UnsupportedOperationException();
		throw exception;
	}

	
	public boolean retainAll(Collection<?> c)
			throws UnsupportedOperationException {
		UnsupportedOperationException exception = new UnsupportedOperationException();
		throw exception;
	}

	
	public Entry set(int index, Entry element)
			throws UnsupportedOperationException {
		UnsupportedOperationException exception = new UnsupportedOperationException();
		throw exception;
	}
}
